#!/usr/bin/env python
# -*- coding: utf-8 -*-


from pymongo import MongoClient, errors
import logging
import sys

logging.basicConfig(level=logging.INFO)

MONGO_HOST = 'localhost'
MONGO_PORT = 27017


def material(inputfile, model):
    if model == "user":
        return user_to_movie(inputfile)
    elif model == "movie":
        return movie_to_user(inputfile)


def user_to_movie(inputfile):
    records = []
    with open(inputfile) as f:
        # items = f.readline().strip().split("::")
        user = ""
        movies = []
        for row in f:
            # userID::movieID::rating::timestamp
            items = row.strip().split(",")
            if items[0] == user:
                movies.append((items[1], items[2]))
            else:
                records.append({'_id': user, 'movies': movies})
                user = items[0]
                movies = [(items[1], items[2])]
    return records


def movie_to_user(inputfile):
    records = []
    with open(inputfile) as f:
        movie = ""
        users = []
        for row in f:
            items = row.strip().split(",")
            if items[1] == movie:
                users.append((items[0], items[2]))
            else:
                records.append({'_id': movie, 'users': users})
                movie = items[1]
                users = [(items[0], items[2])]
    return records


def load_movies(inputfile):
    with open(inputfile) as f:
        for row in f:
            yield row.strip().split("::")[0]
    # return movies


def find_adjacent(movies, db):
    # records = dict()
    collect_movie = db.movie
    collect_user = db.user
    for k in movies:
        logging.info("-> scan movie [{}] to find adjacent".format(k))
        adj_movies = set()
        rows = collect_movie.find_one({"_id": k})
        if not rows:
            logging.warning(
                "cannot find movie: [{}] - records: {}".format(k, rows))
            continue
        users = [x[0] for x in rows["users"]]
        for u in users:
            rs = collect_user.find_one({"_id": u})
            if not rs:
                logging.warning("user: {} has no movies rating".format(u))
                continue
            rs = [x[0] for x in rs["movies"]]
            adj_movies.update(set(rs))

        record = {'_id': k, 'adjacence': list(adj_movies)}
        # logging.debug("movie {} -> {}".format(k, record))
        yield record
    # return records


def bulks(collection, docs):
    for doc in docs:
        if doc:
            try:
                collection.insert(doc)
                logging.info("inserted successful...")
            except errors.DuplicateKeyError:
                pass


def print_usage():
    usage = '''
Usage:
    python analyse  [inputfile]  [model\\n
    \tpython analyse  train_user.dat  user
    \tpython analyse  train_movie.dat  movie
    \tpython analyse  movies.dat  adj
        '''
    print(usage)


if __name__ == '__main__':
    opts = sys.argv[1:]
    if len(opts) != 2:
        print_usage()
        sys.exit(-1)
    inf = opts[0]
    model = opts[1]
    print('connect to database...\n')
    client = MongoClient(MONGO_HOST, MONGO_PORT)
    db = client.movieRecommend

    print('loading dataset...\n')
    if model == "adj":
        collection = db.adjacence
        movies = load_movies(inf)
        docs = find_adjacent(movies, db)
    else:
        collection = db[model]
        docs = material(inf, model)

    print('start uploading...\n')
    bulks(collection, docs)

    print(':)  complete!')
